import unittest
from urllib.parse import quote

from pyramid.testing import cleanUp
from pyramid.util import text_


class TraversalPathTests(unittest.TestCase):
    def _callFUT(self, path):
        from pyramid.traversal import traversal_path

        return traversal_path(path)

    def test_utf8(self):
        la = b'La Pe\xc3\xb1a'
        encoded = quote(la)
        decoded = text_(la, 'utf-8')
        path = '/'.join([encoded, encoded])
        result = self._callFUT(path)
        self.assertEqual(result, (decoded, decoded))

    def test_utf16(self):
        from pyramid.exceptions import URLDecodeError

        la = text_(b'La Pe\xc3\xb1a', 'utf-8').encode('utf-16')
        encoded = quote(la)
        path = '/'.join([encoded, encoded])
        self.assertRaises(URLDecodeError, self._callFUT, path)

    def test_unicode_highorder_chars(self):
        path = text_('/%E6%B5%81%E8%A1%8C%E8%B6%8B%E5%8A%BF')
        self.assertEqual(
            self._callFUT(path),
            (text_('\u6d41\u884c\u8d8b\u52bf', 'unicode_escape'),),
        )

    def test_element_urllquoted(self):
        self.assertEqual(
            self._callFUT('/foo/space%20thing/bar'),
            (text_('foo'), text_('space thing'), text_('bar')),
        )

    def test_unicode_undecodeable_to_ascii(self):
        path = text_(b'/La Pe\xc3\xb1a', 'utf-8')
        self.assertRaises(UnicodeEncodeError, self._callFUT, path)


class TraversalPathInfoTests(unittest.TestCase):
    def _callFUT(self, path):
        from pyramid.traversal import traversal_path_info

        return traversal_path_info(path)

    def test_path_startswith_endswith(self):
        self.assertEqual(self._callFUT('/foo/'), (text_('foo'),))

    def test_empty_elements(self):
        self.assertEqual(self._callFUT('foo///'), (text_('foo'),))

    def test_onedot(self):
        self.assertEqual(
            self._callFUT('foo/./bar'), (text_('foo'), text_('bar'))
        )

    def test_twodots(self):
        self.assertEqual(self._callFUT('foo/../bar'), (text_('bar'),))

    def test_twodots_at_start(self):
        self.assertEqual(self._callFUT('../../bar'), (text_('bar'),))

    def test_segments_are_unicode(self):
        result = self._callFUT('/foo/bar')
        self.assertEqual(type(result[0]), str)
        self.assertEqual(type(result[1]), str)

    def test_same_value_returned_if_cached(self):
        result1 = self._callFUT('/foo/bar')
        result2 = self._callFUT('/foo/bar')
        self.assertEqual(result1, (text_('foo'), text_('bar')))
        self.assertEqual(result2, (text_('foo'), text_('bar')))

    def test_unicode_simple(self):
        path = text_('/abc')
        self.assertEqual(self._callFUT(path), (text_('abc'),))

    def test_highorder(self):
        la = b'La Pe\xc3\xb1a'
        latin1 = text_(la)
        result = self._callFUT(latin1)
        self.assertEqual(result, (text_(la, 'utf-8'),))

    def test_highorder_undecodeable(self):
        from pyramid.exceptions import URLDecodeError

        notlatin1 = text_(b'La Pe\xc3\xb1a', 'utf-8')
        self.assertRaises(URLDecodeError, self._callFUT, notlatin1)


class ResourceTreeTraverserTests(unittest.TestCase):
    def setUp(self):
        cleanUp()

    def tearDown(self):
        cleanUp()

    def _getTargetClass(self):
        from pyramid.traversal import ResourceTreeTraverser

        return ResourceTreeTraverser

    def _makeOne(self, *arg, **kw):
        klass = self._getTargetClass()
        return klass(*arg, **kw)

    def _getEnviron(self, **kw):
        environ = {}
        environ.update(kw)
        return environ

    def test_class_conforms_to_ITraverser(self):
        from zope.interface.verify import verifyClass

        from pyramid.interfaces import ITraverser

        verifyClass(ITraverser, self._getTargetClass())

    def test_instance_conforms_to_ITraverser(self):
        from zope.interface.verify import verifyObject

        from pyramid.interfaces import ITraverser

        context = DummyContext()
        verifyObject(ITraverser, self._makeOne(context))

    def test_call_with_empty_pathinfo(self):
        policy = self._makeOne(None)
        environ = self._getEnviron()
        request = DummyRequest(environ, path_info='')
        result = policy(request)
        self.assertEqual(result['context'], None)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], policy.root)
        self.assertEqual(result['virtual_root'], policy.root)
        self.assertEqual(result['virtual_root_path'], ())

    def test_call_with_pathinfo_KeyError(self):
        policy = self._makeOne(None)
        environ = self._getEnviron()
        request = DummyRequest(environ, toraise=KeyError)
        result = policy(request)
        self.assertEqual(result['context'], None)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], policy.root)
        self.assertEqual(result['virtual_root'], policy.root)
        self.assertEqual(result['virtual_root_path'], ())

    def test_call_with_pathinfo_highorder(self):
        path = text_(b'/Qu\xc3\xa9bec', 'utf-8')
        foo = DummyContext(None, path)
        root = DummyContext(foo, 'root')
        policy = self._makeOne(root)
        environ = self._getEnviron()
        request = DummyRequest(environ, path_info=path)
        result = policy(request)
        self.assertEqual(result['context'], foo)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(result['traversed'], (path[1:],))
        self.assertEqual(result['root'], policy.root)
        self.assertEqual(result['virtual_root'], policy.root)
        self.assertEqual(result['virtual_root_path'], ())

    def test_call_pathel_with_no_getitem(self):
        policy = self._makeOne(None)
        environ = self._getEnviron()
        request = DummyRequest(environ, path_info=text_('/foo/bar'))
        result = policy(request)
        self.assertEqual(result['context'], None)
        self.assertEqual(result['view_name'], 'foo')
        self.assertEqual(result['subpath'], ('bar',))
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], policy.root)
        self.assertEqual(result['virtual_root'], policy.root)
        self.assertEqual(result['virtual_root_path'], ())

    def test_call_withconn_getitem_emptypath_nosubpath(self):
        root = DummyContext()
        policy = self._makeOne(root)
        environ = self._getEnviron()
        request = DummyRequest(environ, path_info=text_(''))
        result = policy(request)
        self.assertEqual(result['context'], root)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], root)
        self.assertEqual(result['virtual_root'], root)
        self.assertEqual(result['virtual_root_path'], ())

    def test_call_withconn_getitem_withpath_nosubpath(self):
        foo = DummyContext()
        root = DummyContext(foo)
        policy = self._makeOne(root)
        environ = self._getEnviron()
        request = DummyRequest(environ, path_info=text_('/foo/bar'))
        result = policy(request)
        self.assertEqual(result['context'], foo)
        self.assertEqual(result['view_name'], 'bar')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(result['traversed'], (text_('foo'),))
        self.assertEqual(result['root'], root)
        self.assertEqual(result['virtual_root'], root)
        self.assertEqual(result['virtual_root_path'], ())

    def test_call_withconn_getitem_withpath_withsubpath(self):
        foo = DummyContext()
        root = DummyContext(foo)
        policy = self._makeOne(root)
        environ = self._getEnviron()
        request = DummyRequest(environ, path_info=text_('/foo/bar/baz/buz'))
        result = policy(request)
        self.assertEqual(result['context'], foo)
        self.assertEqual(result['view_name'], 'bar')
        self.assertEqual(result['subpath'], ('baz', 'buz'))
        self.assertEqual(result['traversed'], (text_('foo'),))
        self.assertEqual(result['root'], root)
        self.assertEqual(result['virtual_root'], root)
        self.assertEqual(result['virtual_root_path'], ())

    def test_call_with_explicit_viewname(self):
        foo = DummyContext()
        root = DummyContext(foo)
        policy = self._makeOne(root)
        environ = self._getEnviron()
        request = DummyRequest(environ, path_info=text_('/@@foo'))
        result = policy(request)
        self.assertEqual(result['context'], root)
        self.assertEqual(result['view_name'], 'foo')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], root)
        self.assertEqual(result['virtual_root'], root)
        self.assertEqual(result['virtual_root_path'], ())

    def test_call_with_vh_root(self):
        environ = self._getEnviron(HTTP_X_VHM_ROOT='/foo/bar')
        baz = DummyContext(None, 'baz')
        bar = DummyContext(baz, 'bar')
        foo = DummyContext(bar, 'foo')
        root = DummyContext(foo, 'root')
        policy = self._makeOne(root)
        request = DummyRequest(environ, path_info=text_('/baz'))
        result = policy(request)
        self.assertEqual(result['context'], baz)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(
            result['traversed'], (text_('foo'), text_('bar'), text_('baz'))
        )
        self.assertEqual(result['root'], root)
        self.assertEqual(result['virtual_root'], bar)
        self.assertEqual(
            result['virtual_root_path'], (text_('foo'), text_('bar'))
        )

    def test_call_with_vh_root2(self):
        environ = self._getEnviron(HTTP_X_VHM_ROOT='/foo')
        baz = DummyContext(None, 'baz')
        bar = DummyContext(baz, 'bar')
        foo = DummyContext(bar, 'foo')
        root = DummyContext(foo, 'root')
        policy = self._makeOne(root)
        request = DummyRequest(environ, path_info=text_('/bar/baz'))
        result = policy(request)
        self.assertEqual(result['context'], baz)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(
            result['traversed'], (text_('foo'), text_('bar'), text_('baz'))
        )
        self.assertEqual(result['root'], root)
        self.assertEqual(result['virtual_root'], foo)
        self.assertEqual(result['virtual_root_path'], (text_('foo'),))

    def test_call_with_vh_root3(self):
        environ = self._getEnviron(HTTP_X_VHM_ROOT='/')
        baz = DummyContext()
        bar = DummyContext(baz)
        foo = DummyContext(bar)
        root = DummyContext(foo)
        policy = self._makeOne(root)
        request = DummyRequest(environ, path_info=text_('/foo/bar/baz'))
        result = policy(request)
        self.assertEqual(result['context'], baz)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(
            result['traversed'], (text_('foo'), text_('bar'), text_('baz'))
        )
        self.assertEqual(result['root'], root)
        self.assertEqual(result['virtual_root'], root)
        self.assertEqual(result['virtual_root_path'], ())

    def test_call_with_vh_root4(self):
        environ = self._getEnviron(HTTP_X_VHM_ROOT='/foo/bar/baz')
        baz = DummyContext(None, 'baz')
        bar = DummyContext(baz, 'bar')
        foo = DummyContext(bar, 'foo')
        root = DummyContext(foo, 'root')
        policy = self._makeOne(root)
        request = DummyRequest(environ, path_info=text_('/'))
        result = policy(request)
        self.assertEqual(result['context'], baz)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(
            result['traversed'], (text_('foo'), text_('bar'), text_('baz'))
        )
        self.assertEqual(result['root'], root)
        self.assertEqual(result['virtual_root'], baz)
        self.assertEqual(
            result['virtual_root_path'],
            (text_('foo'), text_('bar'), text_('baz')),
        )

    def test_call_with_vh_root_path_root(self):
        policy = self._makeOne(None)
        environ = self._getEnviron(HTTP_X_VHM_ROOT='/')
        request = DummyRequest(environ, path_info=text_('/'))
        result = policy(request)
        self.assertEqual(result['context'], None)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], policy.root)
        self.assertEqual(result['virtual_root'], policy.root)
        self.assertEqual(result['virtual_root_path'], ())

    def test_call_with_vh_root_highorder(self):
        path = text_(b'Qu\xc3\xa9bec', 'utf-8')
        bar = DummyContext(None, 'bar')
        foo = DummyContext(bar, path)
        root = DummyContext(foo, 'root')
        policy = self._makeOne(root)
        vhm_root = b'/Qu\xc3\xa9bec'.decode('latin-1')
        environ = self._getEnviron(HTTP_X_VHM_ROOT=vhm_root)
        request = DummyRequest(environ, path_info=text_('/bar'))
        result = policy(request)
        self.assertEqual(result['context'], bar)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(result['traversed'], (path, text_('bar')))
        self.assertEqual(result['root'], policy.root)
        self.assertEqual(result['virtual_root'], foo)
        self.assertEqual(result['virtual_root_path'], (path,))

    def test_path_info_raises_unicodedecodeerror(self):
        from pyramid.exceptions import URLDecodeError

        foo = DummyContext()
        root = DummyContext(foo)
        policy = self._makeOne(root)
        environ = self._getEnviron()
        toraise = UnicodeDecodeError('ascii', b'a', 2, 3, '5')
        request = DummyRequest(environ, toraise=toraise)
        request.matchdict = None
        self.assertRaises(URLDecodeError, policy, request)

    def test_withroute_nothingfancy(self):
        resource = DummyContext()
        traverser = self._makeOne(resource)
        request = DummyRequest({})
        request.matchdict = {}
        result = traverser(request)
        self.assertEqual(result['context'], resource)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], resource)
        self.assertEqual(result['virtual_root'], resource)
        self.assertEqual(result['virtual_root_path'], ())

    def test_withroute_with_subpath_string(self):
        resource = DummyContext()
        traverser = self._makeOne(resource)
        matchdict = {'subpath': '/a/b/c'}
        request = DummyRequest({})
        request.matchdict = matchdict
        result = traverser(request)
        self.assertEqual(result['context'], resource)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ('a', 'b', 'c'))
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], resource)
        self.assertEqual(result['virtual_root'], resource)
        self.assertEqual(result['virtual_root_path'], ())

    def test_withroute_with_subpath_tuple(self):
        resource = DummyContext()
        traverser = self._makeOne(resource)
        matchdict = {'subpath': ('a', 'b', 'c')}
        request = DummyRequest({})
        request.matchdict = matchdict
        result = traverser(request)
        self.assertEqual(result['context'], resource)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ('a', 'b', 'c'))
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], resource)
        self.assertEqual(result['virtual_root'], resource)
        self.assertEqual(result['virtual_root_path'], ())

    def test_withroute_and_traverse_string(self):
        resource = DummyContext()
        traverser = self._makeOne(resource)
        matchdict = {'traverse': text_('foo/bar')}
        request = DummyRequest({})
        request.matchdict = matchdict
        result = traverser(request)
        self.assertEqual(result['context'], resource)
        self.assertEqual(result['view_name'], 'foo')
        self.assertEqual(result['subpath'], ('bar',))
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], resource)
        self.assertEqual(result['virtual_root'], resource)
        self.assertEqual(result['virtual_root_path'], ())

    def test_withroute_and_traverse_tuple(self):
        resource = DummyContext()
        traverser = self._makeOne(resource)
        matchdict = {'traverse': ('foo', 'bar')}
        request = DummyRequest({})
        request.matchdict = matchdict
        result = traverser(request)
        self.assertEqual(result['context'], resource)
        self.assertEqual(result['view_name'], 'foo')
        self.assertEqual(result['subpath'], ('bar',))
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], resource)
        self.assertEqual(result['virtual_root'], resource)
        self.assertEqual(result['virtual_root_path'], ())

    def test_withroute_and_traverse_empty(self):
        resource = DummyContext()
        traverser = self._makeOne(resource)
        matchdict = {'traverse': ''}
        request = DummyRequest({})
        request.matchdict = matchdict
        result = traverser(request)
        self.assertEqual(result['context'], resource)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], resource)
        self.assertEqual(result['virtual_root'], resource)
        self.assertEqual(result['virtual_root_path'], ())

    def test_withroute_and_traverse_and_vroot(self):
        abc = DummyContext()
        resource = DummyContext(next=abc)
        environ = self._getEnviron(HTTP_X_VHM_ROOT='/abc')
        request = DummyRequest(environ)
        traverser = self._makeOne(resource)
        matchdict = {'traverse': text_('/foo/bar')}
        request.matchdict = matchdict
        result = traverser(request)
        self.assertEqual(result['context'], abc)
        self.assertEqual(result['view_name'], 'foo')
        self.assertEqual(result['subpath'], ('bar',))
        self.assertEqual(result['traversed'], ('abc', 'foo'))
        self.assertEqual(result['root'], resource)
        self.assertEqual(result['virtual_root'], abc)
        self.assertEqual(result['virtual_root_path'], ('abc',))


class FindInterfaceTests(unittest.TestCase):
    def _callFUT(self, context, iface):
        from pyramid.traversal import find_interface

        return find_interface(context, iface)

    def test_it_interface(self):
        baz = DummyContext()
        bar = DummyContext(baz)
        foo = DummyContext(bar)
        root = DummyContext(foo)
        root.__parent__ = None
        root.__name__ = 'root'
        foo.__parent__ = root
        foo.__name__ = 'foo'
        bar.__parent__ = foo
        bar.__name__ = 'bar'
        baz.__parent__ = bar
        baz.__name__ = 'baz'
        from zope.interface import Interface, directlyProvides

        class IFoo(Interface):
            pass

        directlyProvides(root, IFoo)
        result = self._callFUT(baz, IFoo)
        self.assertEqual(result.__name__, 'root')

    def test_it_class(self):
        class DummyRoot:
            def __init__(self, child):
                self.child = child

        baz = DummyContext()
        bar = DummyContext(baz)
        foo = DummyContext(bar)
        root = DummyRoot(foo)
        root.__parent__ = None
        root.__name__ = 'root'
        foo.__parent__ = root
        foo.__name__ = 'foo'
        bar.__parent__ = foo
        bar.__name__ = 'bar'
        baz.__parent__ = bar
        baz.__name__ = 'baz'
        result = self._callFUT(baz, DummyRoot)
        self.assertEqual(result.__name__, 'root')


class FindRootTests(unittest.TestCase):
    def _callFUT(self, context):
        from pyramid.traversal import find_root

        return find_root(context)

    def test_it(self):
        dummy = DummyContext()
        baz = DummyContext()
        baz.__parent__ = dummy
        baz.__name__ = 'baz'
        dummy.__parent__ = None
        dummy.__name__ = None
        result = self._callFUT(baz)
        self.assertEqual(result, dummy)


class FindResourceTests(unittest.TestCase):
    def _callFUT(self, context, name):
        from pyramid.traversal import find_resource

        return find_resource(context, name)

    def _registerTraverser(self, traverser):
        from pyramid.threadlocal import get_current_registry

        reg = get_current_registry()
        from zope.interface import Interface

        from pyramid.interfaces import ITraverser

        reg.registerAdapter(traverser, (Interface,), ITraverser)

    def test_list(self):
        resource = DummyContext()
        traverser = make_traverser({'context': resource, 'view_name': ''})
        self._registerTraverser(traverser)
        result = self._callFUT(resource, [''])
        self.assertEqual(result, resource)
        self.assertEqual(resource.request.environ['PATH_INFO'], '/')

    def test_generator(self):
        resource = DummyContext()
        traverser = make_traverser({'context': resource, 'view_name': ''})
        self._registerTraverser(traverser)

        def foo():
            yield ''

        result = self._callFUT(resource, foo())
        self.assertEqual(result, resource)
        self.assertEqual(resource.request.environ['PATH_INFO'], '/')

    def test_self_string_found(self):
        resource = DummyContext()
        traverser = make_traverser({'context': resource, 'view_name': ''})
        self._registerTraverser(traverser)
        result = self._callFUT(resource, '')
        self.assertEqual(result, resource)
        self.assertEqual(resource.request.environ['PATH_INFO'], '')

    def test_self_tuple_found(self):
        resource = DummyContext()
        traverser = make_traverser({'context': resource, 'view_name': ''})
        self._registerTraverser(traverser)
        result = self._callFUT(resource, ())
        self.assertEqual(result, resource)
        self.assertEqual(resource.request.environ['PATH_INFO'], '')

    def test_relative_string_found(self):
        resource = DummyContext()
        baz = DummyContext()
        traverser = make_traverser({'context': baz, 'view_name': ''})
        self._registerTraverser(traverser)
        result = self._callFUT(resource, 'baz')
        self.assertEqual(result, baz)
        self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')

    def test_relative_tuple_found(self):
        resource = DummyContext()
        baz = DummyContext()
        traverser = make_traverser({'context': baz, 'view_name': ''})
        self._registerTraverser(traverser)
        result = self._callFUT(resource, ('baz',))
        self.assertEqual(result, baz)
        self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')

    def test_relative_string_notfound(self):
        resource = DummyContext()
        baz = DummyContext()
        traverser = make_traverser({'context': baz, 'view_name': 'bar'})
        self._registerTraverser(traverser)
        self.assertRaises(KeyError, self._callFUT, resource, 'baz')
        self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')

    def test_relative_tuple_notfound(self):
        resource = DummyContext()
        baz = DummyContext()
        traverser = make_traverser({'context': baz, 'view_name': 'bar'})
        self._registerTraverser(traverser)
        self.assertRaises(KeyError, self._callFUT, resource, ('baz',))
        self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')

    def test_absolute_string_found(self):
        root = DummyContext()
        resource = DummyContext()
        resource.__parent__ = root
        resource.__name__ = 'baz'
        traverser = make_traverser({'context': root, 'view_name': ''})
        self._registerTraverser(traverser)
        result = self._callFUT(resource, '/')
        self.assertEqual(result, root)
        self.assertEqual(root.wascontext, True)
        self.assertEqual(root.request.environ['PATH_INFO'], '/')

    def test_absolute_tuple_found(self):
        root = DummyContext()
        resource = DummyContext()
        resource.__parent__ = root
        resource.__name__ = 'baz'
        traverser = make_traverser({'context': root, 'view_name': ''})
        self._registerTraverser(traverser)
        result = self._callFUT(resource, ('',))
        self.assertEqual(result, root)
        self.assertEqual(root.wascontext, True)
        self.assertEqual(root.request.environ['PATH_INFO'], '/')

    def test_absolute_string_notfound(self):
        root = DummyContext()
        resource = DummyContext()
        resource.__parent__ = root
        resource.__name__ = 'baz'
        traverser = make_traverser({'context': root, 'view_name': 'fuz'})
        self._registerTraverser(traverser)
        self.assertRaises(KeyError, self._callFUT, resource, '/')
        self.assertEqual(root.wascontext, True)
        self.assertEqual(root.request.environ['PATH_INFO'], '/')

    def test_absolute_tuple_notfound(self):
        root = DummyContext()
        resource = DummyContext()
        resource.__parent__ = root
        resource.__name__ = 'baz'
        traverser = make_traverser({'context': root, 'view_name': 'fuz'})
        self._registerTraverser(traverser)
        self.assertRaises(KeyError, self._callFUT, resource, ('',))
        self.assertEqual(root.wascontext, True)
        self.assertEqual(root.request.environ['PATH_INFO'], '/')

    def test_absolute_unicode_found(self):
        # test for bug wiggy found in wild, traceback stack:
        # root = '/%E6%B5%81%E8%A1%8C%E8%B6%8B%E5%8A%BF'
        # wiggy's code: section=find_resource(page, root)
        # find_resource L76: D = traverse(resource, path)
        # traverse L291: return traverser(request)
        # __call__ line 568: vpath_tuple = traversal_path(vpath)
        # lru_cached line 91: f(*arg)
        # traversal_path line 443: path.encode('ascii')
        # UnicodeEncodeError: 'ascii' codec can't encode characters in
        #     position 1-12: ordinal not in range(128)
        #
        # solution: encode string to ascii in pyramid.traversal.traverse
        # before passing it along to webob as path_info
        from pyramid.traversal import ResourceTreeTraverser

        unprintable = DummyContext()
        root = DummyContext(unprintable)
        unprintable.__parent__ = root
        unprintable.__name__ = text_(
            b'/\xe6\xb5\x81\xe8\xa1\x8c\xe8\xb6\x8b\xe5\x8a\xbf', 'utf-8'
        )
        root.__parent__ = None
        root.__name__ = None
        traverser = ResourceTreeTraverser
        self._registerTraverser(traverser)
        result = self._callFUT(
            root, text_(b'/%E6%B5%81%E8%A1%8C%E8%B6%8B%E5%8A%BF')
        )
        self.assertEqual(result, unprintable)


class ResourcePathTests(unittest.TestCase):
    def _callFUT(self, resource, *elements):
        from pyramid.traversal import resource_path

        return resource_path(resource, *elements)

    def test_it(self):
        baz = DummyContext()
        bar = DummyContext(baz)
        foo = DummyContext(bar)
        root = DummyContext(foo)
        root.__parent__ = None
        root.__name__ = None
        foo.__parent__ = root
        foo.__name__ = 'foo '
        bar.__parent__ = foo
        bar.__name__ = 'bar'
        baz.__parent__ = bar
        baz.__name__ = 'baz'
        result = self._callFUT(baz, 'this/theotherthing', 'that')
        self.assertEqual(result, '/foo%20/bar/baz/this%2Ftheotherthing/that')

    def test_root_default(self):
        root = DummyContext()
        root.__parent__ = None
        root.__name__ = None
        result = self._callFUT(root)
        self.assertEqual(result, '/')

    def test_root_default_emptystring(self):
        root = DummyContext()
        root.__parent__ = None
        root.__name__ = ''
        result = self._callFUT(root)
        self.assertEqual(result, '/')

    def test_root_object_nonnull_name_direct(self):
        root = DummyContext()
        root.__parent__ = None
        root.__name__ = 'flubadub'
        result = self._callFUT(root)
        self.assertEqual(result, 'flubadub')  # insane case

    def test_root_object_nonnull_name_indirect(self):
        root = DummyContext()
        root.__parent__ = None
        root.__name__ = 'flubadub'
        other = DummyContext()
        other.__parent__ = root
        other.__name__ = 'barker'
        result = self._callFUT(other)
        self.assertEqual(result, 'flubadub/barker')  # insane case

    def test_nonroot_default(self):
        root = DummyContext()
        root.__parent__ = None
        root.__name__ = None
        other = DummyContext()
        other.__parent__ = root
        other.__name__ = 'other'
        result = self._callFUT(other)
        self.assertEqual(result, '/other')

    def test_path_with_None_itermediate_names(self):
        root = DummyContext()
        root.__parent__ = None
        root.__name__ = None
        other = DummyContext()
        other.__parent__ = root
        other.__name__ = None
        other2 = DummyContext()
        other2.__parent__ = other
        other2.__name__ = 'other2'
        result = self._callFUT(other2)
        self.assertEqual(result, '//other2')


class ResourcePathTupleTests(unittest.TestCase):
    def _callFUT(self, resource, *elements):
        from pyramid.traversal import resource_path_tuple

        return resource_path_tuple(resource, *elements)

    def test_it(self):
        baz = DummyContext()
        bar = DummyContext(baz)
        foo = DummyContext(bar)
        root = DummyContext(foo)
        root.__parent__ = None
        root.__name__ = None
        foo.__parent__ = root
        foo.__name__ = 'foo '
        bar.__parent__ = foo
        bar.__name__ = 'bar'
        baz.__parent__ = bar
        baz.__name__ = 'baz'
        result = self._callFUT(baz, 'this/theotherthing', 'that')
        self.assertEqual(
            result, ('', 'foo ', 'bar', 'baz', 'this/theotherthing', 'that')
        )

    def test_root_default(self):
        root = DummyContext()
        root.__parent__ = None
        root.__name__ = None
        result = self._callFUT(root)
        self.assertEqual(result, ('',))

    def test_root_default_emptystring_name(self):
        root = DummyContext()
        root.__parent__ = None
        root.__name__ = ''
        other = DummyContext()
        other.__parent__ = root
        other.__name__ = 'other'
        result = self._callFUT(other)
        self.assertEqual(result, ('', 'other'))

    def test_nonroot_default(self):
        root = DummyContext()
        root.__parent__ = None
        root.__name__ = None
        other = DummyContext()
        other.__parent__ = root
        other.__name__ = 'other'
        result = self._callFUT(other)
        self.assertEqual(result, ('', 'other'))

    def test_path_with_None_itermediate_names(self):
        root = DummyContext()
        root.__parent__ = None
        root.__name__ = None
        other = DummyContext()
        other.__parent__ = root
        other.__name__ = None
        other2 = DummyContext()
        other2.__parent__ = other
        other2.__name__ = 'other2'
        result = self._callFUT(other2)
        self.assertEqual(result, ('', '', 'other2'))


class QuotePathSegmentTests(unittest.TestCase):
    def _callFUT(self, s):
        from pyramid.traversal import quote_path_segment

        return quote_path_segment(s)

    def test_unicode(self):
        la = text_(b'/La Pe\xc3\xb1a', 'utf-8')
        result = self._callFUT(la)
        self.assertEqual(result, '%2FLa%20Pe%C3%B1a')

    def test_string(self):
        s = '/ hello!'
        result = self._callFUT(s)
        self.assertEqual(result, '%2F%20hello!')

    def test_int(self):
        s = 12345
        result = self._callFUT(s)
        self.assertEqual(result, '12345')

    def test_other(self):
        class Foo:
            def __str__(self):
                return 'abc'

        s = Foo()
        result = self._callFUT(s)
        self.assertEqual(result, 'abc')


class ResourceURLTests(unittest.TestCase):
    def _makeOne(self, context, url):
        return self._getTargetClass()(context, url)

    def _getTargetClass(self):
        from pyramid.traversal import ResourceURL

        return ResourceURL

    def test_instance_conforms_to_IResourceURL(self):
        from zope.interface.verify import verifyObject

        from pyramid.interfaces import IResourceURL

        context = DummyContext()
        request = DummyRequest()
        verifyObject(IResourceURL, self._makeOne(context, request))

    def test_IResourceURL_attributes_with_vroot(self):
        from pyramid.interfaces import VH_ROOT_KEY

        root = DummyContext()
        root.__parent__ = None
        root.__name__ = None
        one = DummyContext()
        one.__parent__ = root
        one.__name__ = 'one'
        two = DummyContext()
        two.__parent__ = one
        two.__name__ = 'two'
        environ = {VH_ROOT_KEY: '/one'}
        request = DummyRequest(environ)
        context_url = self._makeOne(two, request)
        self.assertEqual(context_url.physical_path, '/one/two/')
        self.assertEqual(context_url.virtual_path, '/two/')
        self.assertEqual(
            context_url.physical_path_tuple, ('', 'one', 'two', '')
        )
        self.assertEqual(context_url.virtual_path_tuple, ('', 'two', ''))

    def test_IResourceURL_attributes_vroot_ends_with_slash(self):
        from pyramid.interfaces import VH_ROOT_KEY

        root = DummyContext()
        root.__parent__ = None
        root.__name__ = None
        one = DummyContext()
        one.__parent__ = root
        one.__name__ = 'one'
        two = DummyContext()
        two.__parent__ = one
        two.__name__ = 'two'
        environ = {VH_ROOT_KEY: '/one/'}
        request = DummyRequest(environ)
        context_url = self._makeOne(two, request)
        self.assertEqual(context_url.physical_path, '/one/two/')
        self.assertEqual(context_url.virtual_path, '/two/')
        self.assertEqual(
            context_url.physical_path_tuple, ('', 'one', 'two', '')
        )
        self.assertEqual(context_url.virtual_path_tuple, ('', 'two', ''))

    def test_IResourceURL_attributes_no_vroot(self):
        root = DummyContext()
        root.__parent__ = None
        root.__name__ = None
        one = DummyContext()
        one.__parent__ = root
        one.__name__ = 'one'
        two = DummyContext()
        two.__parent__ = one
        two.__name__ = 'two'
        environ = {}
        request = DummyRequest(environ)
        context_url = self._makeOne(two, request)
        self.assertEqual(context_url.physical_path, '/one/two/')
        self.assertEqual(context_url.virtual_path, '/one/two/')
        self.assertEqual(
            context_url.physical_path_tuple, ('', 'one', 'two', '')
        )
        self.assertEqual(
            context_url.virtual_path_tuple, ('', 'one', 'two', '')
        )


class TestVirtualRoot(unittest.TestCase):
    def setUp(self):
        cleanUp()

    def tearDown(self):
        cleanUp()

    def _callFUT(self, resource, request):
        from pyramid.traversal import virtual_root

        return virtual_root(resource, request)

    def _registerTraverser(self, traverser):
        from pyramid.threadlocal import get_current_registry

        reg = get_current_registry()
        from zope.interface import Interface

        from pyramid.interfaces import ITraverser

        reg.registerAdapter(traverser, (Interface,), ITraverser)

    def test_virtual_root_no_virtual_root_path(self):
        root = DummyContext()
        root.__name__ = None
        root.__parent__ = None
        one = DummyContext()
        one.__name__ = 'one'
        one.__parent__ = root
        request = DummyRequest()
        result = self._callFUT(one, request)
        self.assertEqual(result, root)

    def test_virtual_root_no_virtual_root_path_with_root_on_request(self):
        context = DummyContext()
        context.__parent__ = None
        request = DummyRequest()
        request.root = DummyContext()
        result = self._callFUT(context, request)
        self.assertEqual(result, request.root)

    def test_virtual_root_with_virtual_root_path(self):
        from pyramid.interfaces import VH_ROOT_KEY

        root = DummyContext()
        root.__parent__ = None
        context = DummyContext()
        context.__name__ = 'one'
        context.__parent__ = root
        traversed_to = DummyContext()
        environ = {VH_ROOT_KEY: '/one'}
        request = DummyRequest(environ)
        traverser = make_traverser({'context': traversed_to, 'view_name': ''})
        self._registerTraverser(traverser)
        result = self._callFUT(context, request)
        self.assertEqual(result, traversed_to)
        self.assertEqual(root.request.environ['PATH_INFO'], '/one')

    def test_default(self):
        context = DummyContext()
        request = _makeRequest()
        request.environ['PATH_INFO'] = '/'
        result = self._callFUT(context, request)
        self.assertEqual(result, context)

    def test_default_no_registry_on_request(self):
        context = DummyContext()
        request = _makeRequest()
        del request.registry
        request.environ['PATH_INFO'] = '/'
        result = self._callFUT(context, request)
        self.assertEqual(result, context)


class TraverseTests(unittest.TestCase):
    def setUp(self):
        cleanUp()

    def tearDown(self):
        cleanUp()

    def _callFUT(self, context, name):
        from pyramid.traversal import traverse

        return traverse(context, name)

    def _registerTraverser(self, traverser):
        from pyramid.threadlocal import get_current_registry

        reg = get_current_registry()
        from zope.interface import Interface

        from pyramid.interfaces import ITraverser

        reg.registerAdapter(traverser, (Interface,), ITraverser)

    def test_request_has_registry(self):
        from pyramid.threadlocal import get_current_registry

        resource = DummyContext()
        traverser = make_traverser({'context': resource, 'view_name': ''})
        self._registerTraverser(traverser)
        self._callFUT(resource, [''])
        self.assertEqual(resource.request.registry, get_current_registry())

    def test_list(self):
        resource = DummyContext()
        traverser = make_traverser({'context': resource, 'view_name': ''})
        self._registerTraverser(traverser)
        self._callFUT(resource, [''])
        self.assertEqual(resource.request.environ['PATH_INFO'], '/')

    def test_generator(self):
        resource = DummyContext()
        traverser = make_traverser({'context': resource, 'view_name': ''})
        self._registerTraverser(traverser)

        def foo():
            yield ''

        self._callFUT(resource, foo())
        self.assertEqual(resource.request.environ['PATH_INFO'], '/')

    def test_self_string_found(self):
        resource = DummyContext()
        traverser = make_traverser({'context': resource, 'view_name': ''})
        self._registerTraverser(traverser)
        self._callFUT(resource, '')
        self.assertEqual(resource.request.environ['PATH_INFO'], '')

    def test_self_unicode_found(self):
        resource = DummyContext()
        traverser = make_traverser({'context': resource, 'view_name': ''})
        self._registerTraverser(traverser)
        self._callFUT(resource, text_(''))
        self.assertEqual(resource.request.environ['PATH_INFO'], '')

    def test_self_tuple_found(self):
        resource = DummyContext()
        traverser = make_traverser({'context': resource, 'view_name': ''})
        self._registerTraverser(traverser)
        self._callFUT(resource, ())
        self.assertEqual(resource.request.environ['PATH_INFO'], '')

    def test_relative_string_found(self):
        resource = DummyContext()
        baz = DummyContext()
        traverser = make_traverser({'context': baz, 'view_name': ''})
        self._registerTraverser(traverser)
        self._callFUT(resource, 'baz')
        self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')

    def test_relative_tuple_found(self):
        resource = DummyContext()
        baz = DummyContext()
        traverser = make_traverser({'context': baz, 'view_name': ''})
        self._registerTraverser(traverser)
        self._callFUT(resource, ('baz',))
        self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')

    def test_absolute_string_found(self):
        root = DummyContext()
        resource = DummyContext()
        resource.__parent__ = root
        resource.__name__ = 'baz'
        traverser = make_traverser({'context': root, 'view_name': ''})
        self._registerTraverser(traverser)
        self._callFUT(resource, '/')
        self.assertEqual(root.wascontext, True)
        self.assertEqual(root.request.environ['PATH_INFO'], '/')

    def test_absolute_tuple_found(self):
        root = DummyContext()
        resource = DummyContext()
        resource.__parent__ = root
        resource.__name__ = 'baz'
        traverser = make_traverser({'context': root, 'view_name': ''})
        self._registerTraverser(traverser)
        self._callFUT(resource, ('',))
        self.assertEqual(root.wascontext, True)
        self.assertEqual(root.request.environ['PATH_INFO'], '/')

    def test_empty_sequence(self):
        root = DummyContext()
        resource = DummyContext()
        resource.__parent__ = root
        resource.__name__ = 'baz'
        traverser = make_traverser({'context': root, 'view_name': ''})
        self._registerTraverser(traverser)
        self._callFUT(resource, [])
        self.assertEqual(resource.wascontext, True)
        self.assertEqual(resource.request.environ['PATH_INFO'], '')

    def test_default_traverser(self):
        resource = DummyContext()
        result = self._callFUT(resource, '')
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['context'], resource)

    def test_requestfactory_overridden(self):
        from pyramid.interfaces import IRequestFactory
        from pyramid.request import Request
        from pyramid.threadlocal import get_current_registry

        reg = get_current_registry()

        class MyRequest(Request):
            pass

        reg.registerUtility(MyRequest, IRequestFactory)
        resource = DummyContext()
        traverser = make_traverser({'context': resource, 'view_name': ''})
        self._registerTraverser(traverser)
        self._callFUT(resource, [''])
        self.assertEqual(resource.request.__class__, MyRequest)


class TestDefaultRootFactory(unittest.TestCase):
    def _getTargetClass(self):
        from pyramid.traversal import DefaultRootFactory

        return DefaultRootFactory

    def _makeOne(self, environ):
        return self._getTargetClass()(environ)

    def test_it(self):
        class DummyRequest:
            pass

        root = self._makeOne(DummyRequest())
        self.assertEqual(root.__parent__, None)
        self.assertEqual(root.__name__, None)


class Test__join_path_tuple(unittest.TestCase):
    def _callFUT(self, tup):
        from pyramid.traversal import _join_path_tuple

        return _join_path_tuple(tup)

    def test_empty_tuple(self):
        # tests "or '/'" case
        result = self._callFUT(())
        self.assertEqual(result, '/')

    def test_nonempty_tuple(self):
        result = self._callFUT(('x',))
        self.assertEqual(result, 'x')

    def test_segments_with_unsafes(self):
        safe_segments = tuple(
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
            "-._~!$&'()*+,;=:@"
        )
        result = self._callFUT(safe_segments)
        self.assertEqual(result, '/'.join(safe_segments))
        unsafe_segments = tuple(
            chr(i) for i in range(0x20, 0x80) if not chr(i) in safe_segments
        ) + ('あ',)
        result = self._callFUT(unsafe_segments)
        self.assertEqual(
            result,
            '/'.join(
                ''.join(
                    '%%%02X' % (ord(c) if isinstance(c, str) else c)
                    for c in unsafe_segment.encode('utf-8')
                )
                for unsafe_segment in unsafe_segments
            ),
        )


def make_traverser(result):
    class DummyTraverser:
        def __init__(self, context):
            self.context = context
            context.wascontext = True

        def __call__(self, request):
            self.context.request = request
            return result

    return DummyTraverser


class DummyContext:
    __parent__ = None

    def __init__(self, next=None, name=None):
        self.next = next
        self.__name__ = name

    def __getitem__(self, name):
        if self.next is None:
            raise KeyError(name)
        return self.next

    def __repr__(self):
        return '<DummyContext with name {} at id {}>'.format(
            self.__name__,
            id(self),
        )


class DummyRequest:
    application_url = (
        'http://example.com:5432'  # app_url never ends with slash
    )
    matchdict = None
    matched_route = None

    def __init__(self, environ=None, path_info=text_('/'), toraise=None):
        if environ is None:
            environ = {}
        self.environ = environ
        self._set_path_info(path_info)
        self.toraise = toraise

    def _get_path_info(self):
        if self.toraise:
            raise self.toraise
        return self._path_info

    def _set_path_info(self, v):
        self._path_info = v

    path_info = property(_get_path_info, _set_path_info)


def _makeRequest(environ=None):
    from pyramid.registry import Registry

    request = DummyRequest()
    request.registry = Registry()
    return request
